package ignoreurl

import (
	"strings"

	"gitee.com/tomatomeatman/golang-repository/bricks3/function/filecache"
	"gitee.com/tomatomeatman/golang-repository/bricks3/model/globalvariable"
	"gitee.com/tomatomeatman/golang-repository/bricks3/utils/app/moduleutil"
	"gitee.com/tomatomeatman/golang-repository/bricks3/utils/sqlfactory"
	"github.com/gin-gonic/gin"
)

var (
	cacheSetNotLogin    *filecache.FileCache //路径缓存(全部)免登录
	cacheSubSetNotLogin *filecache.FileCache //路径缓存(仅包含/*的路径)免登录
	cacheSetLogin       *filecache.FileCache //路径缓存(全部)必须登录
	cacheSubSetLogin    *filecache.FileCache //路径缓存(仅包含/*的路径)必须登录
)

// 初始化
func init() {
	service := IgnoreUrlService{}
	go service.initCache() //初始化缓存
	globalvariable.Add("Module@IgnoreUrlService", &service)
}

/**
 * 拦截器忽略路径IgnoreUrl表基本业务操作结构体
 */
type IgnoreUrlService struct {
}

/**
 * 简版'忽略路径'结构体
 */
type SimpleIgonoreUrl struct {
	GsIgnoreUrl    string `json:"sIgnoreUrl" gorm:"column:sIgnoreUrl; type:varchar(5000); NOT NULL; comment:路径集合"`
	GiMustLogin    int64  `json:"iMustLogin" gorm:"column:iMustLogin; type:int(11); NOT NULL; DEFAULT:1; comment:必须登录(布尔值,1:是;2:否)"`
	GsOnlyUserType string `json:"sOnlyUserType" gorm:"column:sOnlyUserType; type:varchar(500); comment:限用户类型(分号分隔)"`
}

/**
 * 验证指定url是否在可忽略的访问路径中(给内部拦截器用,直接返回Boolean)
 * @param sUrl 待检验的url
 * @param isMustLogin 是否必须登录
 * @param sUserType 待检验的用户类型
 * @return
 */
func (iu IgnoreUrlService) CheckIgnoreUrl(sUrl string, isMustLogin bool, sUserType string) (bool, string, interface{}) {
	if strings.TrimSpace(sUrl) == "" {
		return false, "请求检验的Url参数为空", 8001
	}

	iu.initCache() //初始化缓存

	if sUserType != "" {
		sUserType = ";" + sUserType + ";"
	} else {
		sUserType = ""
	}

	//iMustLogin = (null == iMustLogin || iMustLogin.intValue() != 1) ? 2 : 1;//1为必须登录

	//--在免登录的明确路径中找--//

	if item, ok := cacheSetNotLogin.Get(sUrl, nil); ok {
		sUserTypeList := item.(string) //权限限定的用户类型集合
		if sUserTypeList == "" {
			return true, "在免登录的免拦截中发现,并且不限定用户", true
		}

		if strings.Contains(sUserTypeList, sUserType) {
			return true, "在免登录的免拦截中发现,但是限定了用户", true //在免登录的免拦截中发现,但是限定了用户
		}
	}

	//--在免登录的明确路径中中没找到,则可能属于子路径请求--//
	for key, sUserTypeList := range cacheSubSetNotLogin.GetAll() {
		if !strings.Contains(sUrl, key.(string)) {
			continue
		}

		if sUserTypeList == "" {
			return true, "在免登录的免拦截中发现,并且不限定用户", true
		}

		if strings.Contains(sUserTypeList.(string), sUserType) {
			return true, "在免登录的免拦截中发现,但是限定了用户", true //在免登录的免拦截中发现,但是限定了用户
		}
	}

	if !isMustLogin { //未指定要"必须登录"
		return true, "在指定项目中都没有找到可以免拦截的约定", false // MsgEntity.err(8003, "在指定项目中都没有找到可以免拦截的约定")//不符合
	}

	//--指定要"必须登录"--//

	for key, sUserTypeList := range cacheSetLogin.GetAll() {
		if sUrl != key {
			continue
		}

		if sUserTypeList == "" {
			return true, "在必须登录的免拦截(明确路径)中发现,并且不限定用户", true
		}

		if !strings.Contains(sUserTypeList.(string), sUserType) {
			continue //拦截路径的使用限定了用户类型
		}

		return true, "在必须登录的免拦截(明确路径)中发现,并且限定用户", true
	}

	for key, sUserTypeList := range cacheSubSetLogin.GetAll() {
		if !strings.Contains(sUrl, key.(string)) {
			continue
		}

		if sUserTypeList == "" {
			return true, "在必须登录的免拦截(子路径)中发现,并且不限定用户", true
		}

		if !strings.Contains(sUserTypeList.(string), sUserType) {
			continue
		}

		return true, "在必须登录的免拦截(子路径)中发现,并且限定用户", true
	}

	return true, "在指定项目中都没有找到可以免拦截的约定", false //不符合
}

/**
* 初始化缓存
* @return
 */
func (iu IgnoreUrlService) initCache() {
	cacheSetNotLogin, _ = filecache.GetCheck("./temp/cache/IgnoreUrl/NotLogin.gob", -1, false)       //路径缓存(全部)免登录
	cacheSubSetNotLogin, _ = filecache.GetCheck("./temp/cache/IgnoreUrl/SubNotLogin.gob", -1, false) //路径缓存(仅包含/*的路径)免登录
	cacheSetLogin, _ = filecache.GetCheck("./temp/cache/IgnoreUrl/Login.gob", -1, false)             //路径缓存(全部)必须登录
	cacheSubSetLogin, _ = filecache.GetCheck("./temp/cache/IgnoreUrl/SubLogin.gob", -1, false)       //路径缓存(仅包含/*的路径)必须登录

	if cacheSetNotLogin.Size() > 0 {
		return
	}

	iu.createCacheFile() //创建缓存文件
}

/**
 * 创建缓存文件
 * @return
 */
func (iu IgnoreUrlService) createCacheFile() {
	bl, _, res := iu.allIgnoreUrlList()
	if !bl {
		return
	}

	cacheSetNotLogin.Clear()    //路径缓存(全部)免登录
	cacheSubSetNotLogin.Clear() //路径缓存(仅包含/*的路径)免登录
	cacheSetLogin.Clear()       //路径缓存(全部)必须登录
	cacheSubSetLogin.Clear()    //路径缓存(仅包含/*的路径)必须登录

	list := res.([]SimpleIgonoreUrl)
	for _, simpleIgonoreURL := range list {
		sIgnoreUrl := simpleIgonoreURL.GsIgnoreUrl
		if strings.TrimSpace(sIgnoreUrl) == "" {
			continue
		}

		array := strings.Split(sIgnoreUrl, ";")
		for _, val := range array {
			val = strings.TrimSpace(val)
			if val == "" {
				continue
			}

			if simpleIgonoreURL.GiMustLogin != 1 {
				sUserType := ""
				if simpleIgonoreURL.GsOnlyUserType != "" {
					sUserType = ";" + simpleIgonoreURL.GsOnlyUserType + ";"
				}

				cacheSetNotLogin.Set(sUserType, val)
			} else {
				sUserType := ""
				if simpleIgonoreURL.GsOnlyUserType != "" {
					sUserType = ";" + simpleIgonoreURL.GsOnlyUserType + ";"
				}

				cacheSetLogin.Set(sUserType, val)
			}

			if !strings.Contains(val, "/*") { //如果不包含*,说明没有下级
				continue
			}

			val = strings.Replace(val, "/*", "", -1)
			if simpleIgonoreURL.GiMustLogin != 1 { //如果包含*,说明要忽略其下级
				sUserType := ""
				if simpleIgonoreURL.GsOnlyUserType != "" {
					sUserType = ";" + simpleIgonoreURL.GsOnlyUserType + ";"
				}

				cacheSubSetNotLogin.Set(sUserType, val)
			} else {
				sUserType := ""
				if simpleIgonoreURL.GsOnlyUserType != "" {
					sUserType = ";" + simpleIgonoreURL.GsOnlyUserType + ";"
				}

				cacheSubSetLogin.Set(sUserType, val)
			}
		}
	}
}

/**
* 清理缓存
* @return
 */
func (iu IgnoreUrlService) ClearCache(ctx *gin.Context, cacheName, sUser string) (bool, string, interface{}) {
	cacheSetNotLogin.Clear()
	cacheSubSetNotLogin.Clear()
	cacheSetLogin.Clear()
	cacheSubSetLogin.Clear()

	iu.initCache() //初始化缓存,有必要进行,否则会导致拦截器进入访问时第一个会慢

	return true, "请求清理缓存成功！", 8999
}

// 所有不拦截路径(从数据库获取)
func (iu IgnoreUrlService) allIgnoreUrlList() (bool, string, interface{}) {
	text := `SELECT sIgnoreUrl, iMustLogin, sOnlyUserType FROM IgnoreUrl ORDER BY iMustLogin, sOnlyUserType`

	var data []SimpleIgonoreUrl
	bl, msg, res := sqlfactory.Find(moduleutil.GetMainDb(), &data, text)
	if !bl {
		return false, msg, res
	}

	if len(data) < 1 {
		return false, "数据不存在！", 7004
	}

	return true, "查询成功", data
}

// // 转换字符串
// func toStr(data interface{}) string {
// 	if data == nil {
// 		return ""
// 	}

// 	switch obj := data.(type) {
// 	case []uint8:
// 		return byte2Str(obj)
// 	default:
// 		return fmt.Sprintf("%v", obj)
// 	}
// }

// // Byte转Str
// func byte2Str(b []byte) string {
// 	return *(*string)(unsafe.Pointer(&b))
// }

// // 所有不拦截路径(从文件获取)
// func (iu IgnoreUrlService) allIgnoreUrlListByFile() (bool, string, interface{}) {
// 	result := []SimpleIgonoreUrl{}

// 	bl, _, res := fileutil.ReadFromFile("./config/InterceptorIgnore.json")
// 	if bl {
// 		var list []SimpleIgonoreUrl
// 		err := json.Unmarshal([]byte(res.(string)), &list)
// 		if err != nil {
// 			Log.Error("InterceptorIgnore.json文件转换出错：", err)
// 		} else {
// 			result = append(result, list...)
// 		}
// 	}

// 	bl, _, res = fileutil.ReadFromFile("./config/InterceptorIgnoreLogined.json")
// 	if bl {
// 		var list []SimpleIgonoreUrl
// 		err := json.Unmarshal([]byte(res.(string)), &list)
// 		if err != nil {
// 			Log.Error("InterceptorIgnoreLogined.json文件转换出错：", err)
// 		} else {
// 			result = append(result, list...)
// 		}
// 	}

// 	return true, "读取成功", result
// }
